/******************************************************************************
	Cobalt - utility libraries for building XNA games
	Copyright (C) 2008 Philip Djonov

	This program is free software; you can redistribute it and/or modify it
	under the terms of the GNU General Public License as published by the Free
	Software Foundation; either version 2 of the License, or (at your option)
	any later version.

	This program is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
	for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the
	
		Free Software Foundation, Inc.
		51 Franklin Street, Fifth Floor
		Boston, MA  02110-1301, USA.
******************************************************************************/

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;

namespace Cobalt.Content.Pipeline.Graphics
{
	partial class GeometryBufferContent
	{
		public static GeometryBufferContentCollection CompileGeometry( MeshContent mesh, TargetPlatform targetPlatform )
		{
			GeometryBufferContentCollection ret = new GeometryBufferContentCollection();

			for( int e, s = 0; s < mesh.Geometry.Count; s = e )
			{
				int vertCount = mesh.Geometry[s].Vertices.VertexCount;

				for( e = s + 1; e < mesh.Geometry.Count; e++ )
				{
					int newVertCount = vertCount + mesh.Geometry[e].Vertices.VertexCount;

					if( newVertCount >= ushort.MaxValue )
						break;

					vertCount = newVertCount;
				}

				GeometryBufferContent buffer = CompileGeometry( mesh.Geometry, s, e, targetPlatform );
				buffer.Identity = mesh.Identity;

				ret.Add( buffer );
			}

			return ret;
		}

		private static GeometryBufferContent CompileGeometry( GeometryContentCollection geometries, int startIndex, int endIndex,
			TargetPlatform targetPlatform )
		{
			VertexElement[] decl = null;
			List<VertexBufferContent> bufs = new List<VertexBufferContent>( endIndex - startIndex );
			List<IndexCollection> idxs = new List<IndexCollection>( endIndex - startIndex );

			GeometryBufferContent geoBuf = new GeometryBufferContent();

			int byteCount = 0;
			int baseVertex = 0;
			int indexCount = 0;

			for( int i = startIndex; i < endIndex; i++ )
			{
				GeometryContent geom = geometries[i];

				VertexBufferContent vb;
				geom.Vertices.CreateVertexBuffer( out vb, out decl, targetPlatform );

				IndexCollection ib = new IndexCollection();
				foreach( int idx in geom.Indices )
					ib.Add( idx + baseVertex );

				bufs.Add( vb );
				idxs.Add( ib );

				GeometrySurfaceContent surf = new GeometrySurfaceContent();

				surf.Name = geom.Name;
				surf.Identity = geom.Identity;

				surf.Source = geom;

				surf.Material = geom.Material;

				surf.FirstVertex = baseVertex;
				surf.VertexCount = geom.Vertices.VertexCount;
				surf.FirstIndex = indexCount;
				surf.IndexCount = geom.Indices.Count;

				surf.Bounds = BoundingSphere.CreateFromPoints( geom.Vertices.Positions );

				geoBuf.Surfaces.Add( surf );

				byteCount += vb.VertexData.Length;
				baseVertex += geom.Vertices.VertexCount;
				indexCount += geom.Indices.Count;
			}

			geoBuf.VertexBuffer = CombineVertexBuffers( bufs, byteCount );
			geoBuf.VertexDeclaration = decl;
			geoBuf.Indices = CombineIndexBuffers( idxs );

			return geoBuf;
		}

		private static IndexCollection CombineIndexBuffers( List<IndexCollection> ibs )
		{
			IndexCollection ret = new IndexCollection();

			foreach( IndexCollection ib in ibs )
				ret.AddRange( ib );

			return ret;
		}

		private static VertexBufferContent CombineVertexBuffers( List<VertexBufferContent> vbs, int totalSize )
		{
			VertexBufferContent ret = new VertexBufferContent( totalSize );

			int offset = 0;
			foreach( VertexBufferContent vb in vbs )
			{
				Array.Copy( vb.VertexData, 0, ret.VertexData, offset, vb.VertexData.Length );
				offset += vb.VertexData.Length;
			}

			return ret;
		}
	}

}